package cn.thoughtworks.school.services;


import cn.thoughtworks.school.entities.OnlineCodingQuiz;
import cn.thoughtworks.school.entities.Tag;
import cn.thoughtworks.school.entities.User;
import cn.thoughtworks.school.entities.dto.AssignmentQuizData;
import cn.thoughtworks.school.repositories.OnlineCodingQuizRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.persistence.criteria.Predicate;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class OnlineCodingQuizService {
    @Autowired
    private OnlineCodingQuizRepository onlineCodingQuizRepository;
    @Autowired
    private Utils utils;
    @Value("${online-coding-quiz-jenkins-url.add}")
    private String addOnlineCodingQuizJenkinsUrl;
    @Value("${quiz-center-url}")
    private String quizCenterUrl;
    @Autowired
    private QuizService quizService;
    @Value("${online-coding-type}")
    private String type;
    private String githubToken = "ca56d5b5467bc58ed784d14483bc233e87291fd0";
    @Autowired
    private RestTemplate template;
    @Autowired
    private UserCenterService userCenterService;

    public OnlineCodingQuiz createOnlineCodingQuiz(Map onlineCodingQuizMap, User user) {

      OnlineCodingQuiz onlineCodingQuiz = new OnlineCodingQuiz();

      onlineCodingQuiz.setTemplateRepository("生成中");
      onlineCodingQuiz.setMakerId(user.getId());
      onlineCodingQuiz.setTags(utils.formatTags((List<String>) onlineCodingQuizMap.get("tags"), user.getId()));
      onlineCodingQuiz.setDefinitionRepo((String) onlineCodingQuizMap.get("definitionRepo"));
      onlineCodingQuiz.setLanguage((String) onlineCodingQuizMap.get("language"));
      onlineCodingQuiz.setOnlineCodingName((String) onlineCodingQuizMap.get("title"));
      onlineCodingQuiz.setStackId(((Integer) onlineCodingQuizMap.get("stackId")).longValue());
      onlineCodingQuiz.setAvailable(true);
      onlineCodingQuiz.setRemark((String) onlineCodingQuizMap.get("remark"));
      onlineCodingQuiz = onlineCodingQuizRepository.save(onlineCodingQuiz);
      String callbackUrl = quizCenterUrl + "/api/v3/onlineCodingQuizzes/" + onlineCodingQuiz.getId() + "/status";
      MultiValueMap data = new LinkedMultiValueMap();
      data.add("github_token", githubToken);
      data.add("git", onlineCodingQuiz.getDefinitionRepo());
      data.add("callback_url", callbackUrl);

      template.postForObject(addOnlineCodingQuizJenkinsUrl, data, String.class);

      return onlineCodingQuiz;
    }

  public Page getOnlineCodingQuizzesPageable(Pageable pageable, Long id, Long userId, String description, List<String> tags, User user) {
    Long currentOrganizationId = userCenterService.getUserCurrentOrganizationId(user.getId());
    List<Long> quizIds = getQuizIdsByTags(tags);
    Page<OnlineCodingQuiz> homeworkQuizPage = getOnlineCodingQuizPage(currentOrganizationId, pageable, id, userId, description, quizIds);

    return utils.format(homeworkQuizPage, pageable);
  }
  private Page<OnlineCodingQuiz> getOnlineCodingQuizPage(Long organizationId, Pageable pageable, Long id, Long userId, String description, List<Long> quizIds) {
    return onlineCodingQuizRepository.findAll((Specification<OnlineCodingQuiz>) (root, query, criteriaBuilder) -> {
      List<Predicate> predicates = quizService.getDefaultPredicates(organizationId, id, userId, description, quizIds, root, criteriaBuilder);
      return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
    }, pageable);
  }

  private List<Long> getQuizIdsByTags(List<String> tags) {
    List<OnlineCodingQuiz> quizzes = onlineCodingQuizRepository.findQuizzesByTags(tags);
    if (Objects.nonNull(tags) && quizzes.isEmpty()) {
      return Arrays.asList(-1L);
    }
    return quizzes.stream().map(OnlineCodingQuiz::getId).collect(Collectors.toList());
  }

  public List<AssignmentQuizData> copy(List<AssignmentQuizData> onlineCodingQuizzesData) {
    List<Long> ids = onlineCodingQuizzesData.stream().map(AssignmentQuizData::getQuizId).collect(Collectors.toList());
    List<OnlineCodingQuiz> onlineQuizzes = onlineCodingQuizRepository.findByIdIn(ids);

    onlineCodingQuizzesData.forEach(quizData -> {
      Long creatorId = quizData.getCreatorId();
      OnlineCodingQuiz onlineQuiz = onlineQuizzes.stream()
        .filter(quiz -> quiz.getId().equals(quizData.getQuizId()))
        .findFirst().get();
      Set<Tag> tags = quizService.copyTags(quizData.getOrganizationId(), onlineQuiz.getTags(), creatorId);
      Long stackId = quizService.copyStack(quizData.getOrganizationId(), onlineQuiz.getStackId(),creatorId);
      onlineQuiz = OnlineCodingQuiz.copy(onlineQuiz, creatorId, quizData.getOrganizationId(),tags,stackId);
      onlineCodingQuizRepository.save(onlineQuiz);
      quizData.setNewQuizId(onlineQuiz.getId());
    });
    return onlineCodingQuizzesData;
  }
}
